home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _comms / comms / _signature / AC / !Signature / NumModTxt < prev    next >
Text File  |  1992-08-01  |  18KB  |  537 lines

  1. NUMBERS MODULE version 0.08
  2. ===========================
  3.  
  4. (C) Copyright Nick Craig-Wood 1992
  5.  
  6. The module "Numbers" and this documentation "NumModTxt" are public domain. 
  7. You may distribute them freely provided that
  8.  1) both files are always kept together
  9.  2) the files are not altered in any way
  10.  3) no profit is made
  11. If you wish to break any of these conditions get in touch with me at the
  12. address below first.
  13.  
  14. The software and documentation was first published in BBC Acorn User
  15. Magazine, September 1992, and for more information see that issue.
  16.  
  17. These routines started life in 1989 written in C on the university mainframe
  18. in response to a  "Numbers Count" puzzle in PCW.  The problem (or part of
  19. it) was to calculate the biggest prime you could find of the form N!+1. 
  20. However the routines did not get finished in time  for the puzzle deadline. 
  21. In the quest for speed I converted the routines to 68000 code for my  Atari
  22. ST, and then a year later into ARM code.  With an ARM3 the routines run at
  23. the same  speed as they did on the mainframe!
  24.  
  25. Numbers are held in application memory area in a heap, and maintained by
  26. OS_Heap.  Before the module can be used, it must be told about this
  27. heap with Num_InitHeap.  Numbers come in two pieces, the head and the tail. 
  28. All numbers have a head, but need not have a tail.  The head of the number
  29. is a short block in the heap, which points to the tail and keeps the length
  30. and sign of the number, and various other things.  Numbers are passed by
  31. reference only, as pointers to the head of the number.  These are refered to
  32. as NUMs.  For example NUM r0 indicates that r0 is a pointer to the head of a
  33. number.
  34.  
  35. Since NUMs are passed by reference only, if you pass them into procedures
  36. and then alter the values of the input parameters, you are actually
  37. altering the NUM.  So to avoid problems, if you write a procedure which
  38. takes NUMs as parameters for both input and output, it is best to define
  39. some temporary NUMs using Num_Init for the output, and then at the end
  40. Num_Swap the results into the correct place, and Num_Remove the temporary
  41. variables.  All the internal routines of the module work like this, so there
  42. is never any problem with passing the same NUM as input and output.
  43.  
  44. Some of the routines take either NUMs or scalars as arguments.  Scalars are
  45. normal signed or unsigned 32 bit numbers.  All routines expect NUMs to be
  46. tidy (except Num_Tidy).  (A num is tidy if its most significant digit is
  47. non-zero, and if it is zero, then it is positive, and of length 1.  Num_Tidy
  48. accomplishes this.  It is unlikely that a user will need this function.)
  49.  
  50. Any error from the numbers module will be prefixed with "Numbers: ".  If you
  51. pass an invalid NUM to any of the routines, the chances are that OS_Heap
  52. will reply with an error, but not one that makes sense always.  The most
  53. confusing is "Numbers: Heap Full" so beware!  See the end for a short example
  54. program.
  55.  
  56. If you find any bugs, have any comments or queries or wish to use the module
  57. in commercial software please write to
  58.  
  59. Nick Craig-Wood
  60. 4 Victoria Street
  61. Wolverton
  62. Bucks
  63. MK12 5HL.
  64.  
  65. -----------------------------------------------------------------------------
  66.  
  67. NUMBERS SWI
  68. ===========
  69.  
  70. On Entry:        r0-r3 are parameters
  71. On Exit:         r0-r3 are returned as results or corrupted
  72.                  r4-r14 are preserved
  73.  
  74. Interrupts:      Interrupts are enabled
  75.                  Fast interrupts are enabled
  76.  
  77. Processor mode:  Processor is in SVC mode
  78.  
  79. Re-entrancy:     SWIs are not re-entrant
  80.  
  81. Use:             See QUICK REFERENCE, and DEFINITIONS for details
  82.                  All SWIs that are capable of looping respond to ESCAPE
  83.                  See ERRORS section for details of errors returned
  84.  
  85. -----------------------------------------------------------------------------
  86.  
  87. QUICK REFERENCE
  88. ===============
  89.  
  90. NUMBERS HEAP: area in application workspace where all the number are kept
  91. HEAD: 16 byte parameter block in the numbers heap pointing to
  92. TAIL: variable length block containing the value of the number
  93. NUM: meaning a 32 bit integer pointing to a HEAD
  94. INT: meaning a 32 bit integer
  95. SCALAR: meaning a 32 bit integer
  96. FLAG: is either 0 for false, or 1 for true
  97. STRING: a pointer to a 0 terminated ASCII string
  98.  
  99. a,b,c,d represent pointers to NUMs
  100. i,j,k   represent SCALARS
  101. p,q     represent a pointer to memory
  102. f       represents a FLAG
  103. h       represents a HeapPointer as returned by Num_HeapInit in r0
  104.           
  105. SWI                 Parameters  Results  Comments
  106. ===                 ==========  =======  ========
  107. Num_Author          -           -        Prints out some info
  108. Num_InitHeap        p,i         h,a,b,c  h<-HeapPointer, a<-0, b<-1, c<-2
  109. Num_MakeSmallPrimes i           j        Makes primes up to i, # found to j
  110.  
  111. (All the SWIs below need a valid NUM or HeapPointer in r0)
  112.  
  113. Num_Allocate        a,i         -        Allocates i words to TAIL of a
  114. Num_Deallocate      a           -        Removes the TAIL of a
  115. Num_Set             a,i         -        Sets a to signed i
  116. Num_USet            a,i         -        Sets a to unsigned i
  117. Num_Init            h           a        Makes a HEAD and TAIL and pointer a
  118. Num_Remove          a           -        Removes the HEAD and TAIL of a
  119. Num_Equals          a,i         f        Returns truth of a = i
  120. Num_Swap            a,b         -        Swaps a and b.  This is quick.
  121. Num_Move            a,b         -        Sets b to a.  Not so quick.
  122. Num_Clear           a           -        Sets TAIL of a to all zeroes
  123. Num_Tidy            a           -        Reduces a to shortest length
  124. Num_UCmp            a,b         i        Unsigned compare of a-b to i
  125. Num_Cmp             a,b         i        Returns the sign of a-b to i
  126. Num_ScalarCmp       a,i         j        Returns the sign of a-i to j
  127. Num_ScalarAdd       a,i,c       -        c <- a + i
  128. Num_ScalarSub       a,i,c       -        c <- a - i
  129. Num_ScalarMul       a,i,c       -        c <- a * i
  130. Num_ScalarDiv       a,i,c       j        c <- a / i, j <- a MOD i
  131. Num_ScalarMod       a,i         j        j <- a MOD i
  132. Num_SmallFactorN    a,i         k        k=smallest factor of a or 0, try i
  133. Num_SmallFactor     a           k        k=smallest factor of a or 0, try all
  134. Num_Add             a,b,c       -        c <- a + b
  135. Num_Sub             a,b,c       -        c <- a - b
  136. Num_Mul             a,b,c       -        c <- a * b
  137. Num_Div             a,b,c,d     -        c <- a / b, d <- a MOD b
  138. Num_Mod             a,b,c       -        c <- a MOD b
  139. Num_Dump            a           -        Prints a in hex, and other info
  140. Num_ToString        a           p,q      Makes STRING of a to p, end=q
  141.                                          After use do SYS "Num_Deallocate",b
  142. Num_Print           a           -        Prints a in decimal
  143. Num_FromString      a,p         f        Converts STRING at p to a, f=ok
  144. Num_Input           a           f        Gets a decimal input to a, f=ok
  145. Num_Info            h           -        Prints memory usage info
  146. Num_RndScalar       h           i        Makes a random number 0-&FFFFFFFF
  147. Num_SetSeed         h,i         -        Sets seed of rnd generator
  148. Num_Rnd             a,b         -        Makes random number to a, 0 <= a < b
  149. Num_Gcd             a,b,c       -        c <- greatest common divisor a,b
  150. Num_Sqr             a,b         -        b <- square root of a
  151. Num_Pow             a,b,c       -        c <- a ^ b (a to the power b)
  152. Num_PowMod          a,d,c,b     -        d <- (a^b) MOD c
  153. Num_Factorial       a,b         -        b <- a! = a*(a-1)*(a-1)*..*3*2*1
  154. Num_Inv             a,b,c,d     -        Finds c,d: a*c MOD b=d & d=GCD(a,b)
  155. Num_FermatTest      a,i         j        Computes truth of i^(a-1) MOD a = 1
  156. Num_ProbablyPrime   a           j        j <- 0 if not prime, 1 probablyprime
  157.  
  158. -----------------------------------------------------------------------------
  159.  
  160. DEFINITIONS
  161. ===========
  162.  
  163. Num_InitHeap
  164. ------------
  165. This expects r0 as a pointer to a block of memory to be used as a heap, and
  166. r1 as the length of this memory in bytes. This returns a pointer to the
  167. heap in r0 and some nums which are useful consants r1 <- zero, r2 <- one, r3
  168. <- two.  The HeapPointer returned in r0 is required by some of the other
  169. routines.
  170.  
  171.  
  172. Num_Allocate
  173. ------------
  174. This updates NUM r0 to point to a new area of memory of length r1
  175. (in 32-bit words)
  176.  
  177.  
  178. Num_Deallocate
  179. --------------
  180. This releases the memory used by a NUM (tail), and sets its pointers to NULL
  181.  
  182.  
  183. Num_Set
  184. -------
  185. This sets the NUM supplied in r0 to the signed scalar supplied in r1
  186.  
  187.  
  188. Num_Uset
  189. --------
  190. This sets the NUM supplied in r0 to the unsigned scalar supplied in r1
  191.  
  192.  
  193. Num_Init
  194. --------
  195. Expects r0=HeapPointer
  196. This returns the address of a new NUM in r0 For creating new or LOCAL
  197. variables
  198.  
  199.  
  200. Num_Remove
  201. ----------
  202. This removes the allocation for NUM r0 and removes NUM r0 (For removing
  203. LOCAL variables)
  204.  
  205.  
  206. Num_Equals
  207. ----------
  208. This function returns TRUE in r0 if NUM r0 is equal to the single element
  209. supplied in r1
  210.  
  211.  
  212. Num_Swap
  213. --------
  214. This swaps the two NUMs in r0 and r1.  It is a fast way of getting
  215. infromation out of temporary variables, before destroying them
  216.  
  217.  
  218. Num_Move
  219. --------
  220. This moves NUM r0 to NUM r1.  It does this by actually copying the NUM.
  221.  
  222.  
  223. Num_Clear
  224. ---------
  225. This clears the tail of NUM r0 to all zeros
  226.  
  227.  
  228. Num_Tidy
  229. --------
  230. This makes the NUM r0 use as few digits as possible by removing all the
  231. leading zeroes
  232.  
  233.  
  234. Num_UCmp
  235. --------
  236. This returns an unsigned comparison between NUM r0 amd NUM r1 in r0 This is
  237. the SGN(NUM r0 - NUM r1)
  238.  
  239.  
  240. Num_Cmp
  241. -------
  242. This function returns a signed comparison between NUM r0 and NUM r1 It
  243. returns SGN(NUM r0 - NUM r1)
  244.  
  245.  
  246. Num_ScalarCmp
  247. ----------
  248. This function returns a signed comparison between NUM r0 and SCALAR r1 It
  249. returns SGN(NUM r0 - NUM r1)
  250.  
  251.  
  252. Num_ScalarAdd
  253. ----------
  254. This adds NUM r0 to (signed int) r1 into NUM r2
  255.  
  256.  
  257. Num_ScalarSub
  258. ----------
  259. This subtracts NUM r0 - (signed int) r1 into NUM r2
  260.  
  261.  
  262. Num_ScalarDiv
  263. ----------
  264. This multiplies NUM r0 by (unsigned int) r1 into NUM r2
  265.  
  266.  
  267. Num_ScalarMod
  268. ----------
  269. This divides NUM r0 by (unsigned int) r1 returning the (unsigned int)
  270. remainder in r0 int NUM r2
  271.  
  272.  
  273. Num_Mul
  274. -------
  275. NUM r0 * NUM r1 -> NUM r2
  276.  
  277.  
  278. Num_Div
  279. -------
  280. This divides r0 by r1 to give a quotient r2 remainder r3
  281. For "divide and correct algorithm" see Knuth "Seminumerical Algorthms"
  282. section 4.3.1
  283.  
  284.  
  285. Num_Mod
  286. -------
  287. This divides r0 by r1 to remainder r2
  288.  
  289.  
  290. Num_MakeSmallPrimes
  291. -------------------
  292. This makes all the primes up to r0, and stores them in the RMA pointed
  293. to by SmallPrimes. NSmallPrimes is set to the number of primes found.
  294. It deallocates any old SmallPrimes array so this may be called more than
  295. once.  It returns the number of smallprimes found in r0, and a pointer
  296. to the array in r1.  If there are already more than enough SmallPrimes in
  297. the RMA then this will not recalculate.
  298.  
  299.  
  300. Num_Dump
  301. --------
  302. This dumps the number supplied in r0 in Hexadecimal, for debugging
  303.  
  304.  
  305. Num_ToString
  306. ------------
  307. This converts the number pointed to by r0 into a decimal string pointed to
  308. by r0.  When finished with, this memory should be released with
  309. SYS "Num_Heap",3,,r0 It returns the position of the null at the end of the
  310. num in r1
  311.  
  312.  
  313. Num_Print
  314. ---------
  315. This prints out the number supplied in r0.  It prints no spaces or newlines.
  316.  
  317.  
  318. Num_Info
  319. --------
  320. Expects r0=HeapPointer
  321. This provides information on the numbers module
  322.  
  323.  
  324. Num_FromString
  325. --------------
  326. This converts a number in ASCII base 10 pointed to by r1 into the NUM
  327. pointed to by r0, until a character which is not 0-9 is reached.  If this is
  328. a control char then true is returned otherwise false is returned deals with
  329. leading "+","-"," "
  330.  
  331.  
  332. Num_Input
  333. ---------
  334. Inputs a number in base 10 to NUM r0 Returns r0 flagging ok conversion
  335.  
  336.  
  337. Num_RndScalar
  338. -------------
  339. Expects r0=HeapPointer
  340. Produces a random number into r0 from Seed, and updates it, in the range
  341. 0-&FFFFFFFF.  It works using the algorithm x(n+1)=(1664525 * x(n) +
  342. 907633393) MOD 2^32 It is known that the least significant bits are not as
  343. random as the most significant bits, so two consecutive random numbers are
  344. generated, and combined with EOR after having been rotated by 16 bits with
  345. respect to each other.  This halves the period.  Reference; Knuth,
  346. Seminumerical Algorithms 3.3 p102 p84 This is Line 26, with the best
  347. spectral co-efficients for a MOD 2^32 generator, listed in Knuth.  This form
  348. is especially easy to calculate with the ARMs mul instruction. The A term is
  349. calculated as the nearest prime to (1/2-1/3*SQR(3))*2^32.
  350.  
  351.  
  352. Num_SetSeed
  353. -----------
  354. Expects r0=HeapPointer
  355. This sets the internal 32-bit random number generator to the seed supplied in
  356. r1
  357.  
  358.  
  359. Num_Rnd
  360. -------
  361. This generates a random number 0 <= rnd < r0 to r1
  362.  
  363.  
  364. Num_Gcd
  365. -------
  366. This finds the gcd(r0,r1) -> r2 using Euclid's algoritm
  367.  
  368.  
  369. Num_Sqr
  370. -------
  371. This takes the square root of r0 to r1 It uses a second order
  372. Newton-Raphson convergence. This doubles the number of significant figures
  373. on each iteration. Square root of a negative number if returned as 0. It
  374. returns the number of iterations in r0
  375.  
  376.  
  377. Num_Pow
  378. -------
  379. This finds r0 to the power of r1 to r2
  380.  
  381.  
  382. Num_PowMod
  383. ----------
  384. This finds r0 to the power of r1 MOD r2 to r3
  385.  
  386.  
  387. Num_Factorial
  388. -------------
  389. This finds NUM r0 factorial to NUM r1 if r0<=1 then r1=0
  390.  
  391.  
  392. Num_SmallFactorN
  393. ----------------
  394. This sees whether NUM r0 has any small factors.  It requires
  395. Num_MakeSmallPrimes to have been called.  It tests r1 small primes.  It
  396. returns either the factor found, or 0 to show none found in r0
  397.  
  398.  
  399. Num_SmallFactor
  400. ---------------
  401. This sees whether NUM r0 has any small factors.  It requires
  402. Num_MakeSmallPrimes to have been called.  It tests all the small primes
  403. that have been made.  It returns either the factor found, or 0 to show none
  404. found in r0
  405.  
  406.  
  407. Num_Inv
  408. -------
  409. This finds r2 such that r0*r2 MOD r1=r3 AND r3=GCD(r0,r1) so if GCD(r0,r1)=1
  410. (for instance if r1 is prime) then this will compute the inverse MOD r1. This
  411. is adapted from Knuth; Seminumerical Algorithms 4.5.2 pp325
  412.  
  413.  
  414. Num_FermatTest
  415. --------------
  416. This finds whether NUM r0 is a prime with respect to SCALAR r1, using the
  417. fermat test.  That is r0 is not a prime if r1^(r0-1) MOD r0 <> 1 IF
  418. r1^(r0-1) MOD r0=1 THEN r0 may be a prime. r1 must be prime for the test to
  419. work. IE this test returns false if r0 is not prime, or true if r0 might be
  420. prime.  This test is less reliable than Num_ProbablyPrime and takes about
  421. the same time to execute.
  422.  
  423.  
  424. Num_ProbablyPrime
  425. -----------------
  426. This tests whether r0 is prime or not.  The function returns (in r0) false
  427. if the number is not prime, and true if the number is probably prime. The
  428. algorithm will return true with r0 composite with a probability of less than
  429. 0.25.  This algorithm is as in Knuth - Seminumerical algorithms 4.5.4P
  430.  
  431. -----------------------------------------------------------------------------
  432.  
  433. EXAMPLE
  434. -------
  435.  
  436. In the spirit of an illustration is worth 1000 words, here is an example
  437. BASIC program using the numbers module.  It tries to find any primes of the
  438. form 111...111 (these are called rep-units).
  439.  
  440. REM Check to see we have the numbers module
  441. *RMEnsure Numbers 0.0 RMLoad Numbers
  442. *RMEnsure Numbers 0.0 Error 1 Numbers module not found
  443.  
  444. REM put aside some BASIC memory for the Numbers Heap
  445. HeapSize=64*1024
  446. DIM Numbers HeapSize
  447.  
  448. REM Initialise the Heap
  449. SYS "Num_HeapInit",Numbers,HeapSize TO hp%,zero%,one%,two%
  450.  
  451. REM Make some small primes for finding small factors
  452. SYS "Num_MakeSmallPrimes",5000 TO a%
  453. PRINT ;a%;" small primes found"
  454.  
  455. REM This is the number of times we will run Num_ProbablyPrime to be sure
  456. REM a repunit is prime
  457. timestotest=20
  458.  
  459. REM Make the NUM repunit% and start it off at 1
  460. SYS "Num_Init",hp% TO repunit%
  461. SYS "Num_Set",repunit%,1
  462.  
  463. FOR n%=2 TO 100000
  464.   REM repunit=10*repunit+1, ie add 1 digit to the repunit
  465.   SYS "Num_ScalarMul",repunit%,10,repunit%
  466.   SYS "Num_ScalarAdd",repunit%,1,repunit%
  467.  
  468.   PRINT ".";
  469.   REM try to find a small factor of repunit%
  470.   SYS "Num_SmallFactor",repunit% TO composite
  471.   IF composite=0 THEN
  472.    composite=timestotest
  473.    WHILE composite>0
  474.     PRINT "|";
  475.     REM test the primality of repunit% timestotest times
  476.     SYS "Num_ProbablyPrime",repunit% TO pprime
  477.     IF pprime THEN
  478.      composite-=1
  479.     ELSE
  480.      REM if the number is composite but passes a test, this is unusual
  481.      IF composite<>timestotest THEN PRINT "Unusual prime: ";FNprint(repunit%)
  482.      composite=-1
  483.     ENDIF
  484.    ENDWHILE
  485.   ENDIF
  486.   REM print out a prime if we have found one
  487.   IF composite=0 THEN PRINT "R(";n%;") = ";FNprint(repunit%);" is prime"
  488. NEXT n%
  489. END
  490.  
  491. REM This prints NUM a% returning a null string
  492.  
  493. DEF FNprint(a%): SYS "Num_Print",a%: =""
  494.  
  495. -----------------------------------------------------------------------------
  496.  
  497. ERRORS
  498. ------
  499.  
  500. The following errors are unique to the Numbers module.  However the numbers
  501. Module will return any OS errors (such as OS_Heap errors) unchanged, except
  502. for the addition of a prefix of "Numbers: "
  503.  
  504. Numbers module has become corrupted
  505. Returned on initialisation if the Numbers code has been changed (say by a
  506. virus or by a disk error)
  507.  
  508. Numbers: Unknown Operation
  509. Returned when an unimplemented numbers SWI is called
  510.  
  511. Numbers: Escape
  512. Returned when the user pressed Escape in a Looping SWI.
  513.  
  514. Numbers: Invalid Heap or NUM
  515. Returned when HeapPointer is invalid, or an Invalid pointer to a NUM is given
  516.  
  517. Numbers: Divide by 0 in Num_ScalarDiv
  518.  
  519. Numbers: Divide by 0 in Num_Div
  520.  
  521. Numbers: Addback Failed in Num_Div
  522. This error should never occur.  If it does, I would be interested to know!
  523.  
  524. Numbers: N > NSmallPrimes in Num_SmallFactorN
  525. Returned when you ask for more SmallPrimes than have been calculated.
  526.  
  527. -----------------------------------------------------------------------------
  528.  
  529. REFERENCES
  530. ==========
  531.  
  532. Books I have found useful whilst writing this module
  533.  
  534. "SemiNumerical Algorithms" (2nd Edition) D.E.Knuth, Addison-Wesley
  535. "Elementary Number Theory" D.M.Burton, Allyn and Bacon
  536. "Cryptography: an introduction to computer security" J.Seberry, Prentice Hall
  537.